package com.carsa.blackberry.util.persistence;

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;

import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;

import net.rim.device.api.io.Seekable;

import com.carsa.blackberry.util.Logger;

/**
 * @author Nahuel Barrios.
 * @since 23/07/2010.
 * @version 1.0
 */
public class FileHandlerImpl implements FileHandler {

    private FileConnection _fileConnection = null;
    private int            _registryLenght = -1;

    public String getFileData() throws java.io.IOException {
	if (_fileConnection == null || !_fileConnection.isOpen())
	    return null;

	DataInputStream inputData = null;
	byte[] bytesToReturn = null;

	try {
	    inputData = (DataInputStream) _fileConnection.openDataInputStream();

	    // Reads the file's data.
	    bytesToReturn = this.readFully(inputData);

	    return new String(bytesToReturn);
	}
	catch (Exception e) {
	    e.printStackTrace();
	    return null;
	}
    }

    public String getFileLine(int idx) {
	if (_fileConnection == null || !_fileConnection.isOpen() || _registryLenght == -1)
	    return null;

	idx = (idx - 1) * _registryLenght;

	DataInputStream inputData = null;
	byte[] bytesToReturn = null;

	try {
	    inputData = (DataInputStream) _fileConnection.openDataInputStream();

	    // Reads the file's data.
	    bytesToReturn = this.readFromIdx(inputData, idx, _registryLenght);

	    inputData.close();

	    return new String(bytesToReturn);
	}
	catch (Exception e) {
	    e.printStackTrace();
	    return null;
	}
    }

    public boolean entablishConnection(String filePath) {
	try {
	    if (_fileConnection != null && _fileConnection.isOpen())
		_fileConnection.close();

	    _fileConnection = (FileConnection) Connector.open(FileHandler.URL_PREFFIX + filePath);

	    // If no exception is thrown, then the URI is valid, but the file may or may not exist.
	    if (!_fileConnection.exists()) {
		_fileConnection.create(); // Create the file if it doesn't exist
		Logger.logInfo("Se creo el archivo: " + filePath);
	    } else
		Logger.logInfo("El archivo " + filePath + " ya existia.");
	}
	catch (IOException e) {
	    Logger.logError(e);
	    return false;
	}

	return true;
    }

    public boolean entablishConnection(String filePath, int registryLenght) {
	_registryLenght = registryLenght;

	return this.entablishConnection(filePath);
    }

    public boolean writeFile(String data) {
	if (_fileConnection == null || !_fileConnection.isOpen())
	    return false;

	OutputStream outStream = null;
	try {
	    outStream = _fileConnection.openOutputStream();
	    outStream.write(data.getBytes());
	}
	catch (IOException e) {
	    e.printStackTrace();
	}

	try {
	    outStream.close();
	}
	catch (IOException e) {
	    e.printStackTrace();
	    return true;
	}

	return true;
    }

    private byte[] readFromIdx(DataInputStream inputData, int idx, int len) {
	byte[] data = new byte[len];

	if (inputData instanceof Seekable) {
	    try {

		((Seekable) inputData).setPosition(idx);
		inputData.read(data, 0, len);

	    }
	    catch (IOException e) {
		e.printStackTrace();
	    }
	}
	return data;
    }

    /**
     * Gets every available byte of the file and then close the stream. <b>Note: </b>This is not the most efficient way
     * to read the data of a file.
     * 
     * @return All availables bytes of the file.
     */
    public byte[] readFully(DataInputStream input) throws java.io.IOException {
	ByteArrayOutputStream bo = null;
	bo = new ByteArrayOutputStream();
	try {

	    for (byte b = 0; (b = input.readByte()) != -1;)
		bo.write(b);

	}
	catch (IOException e) {
	    e.printStackTrace();
	}

	byte[] bytes = bo.toByteArray();

	// Liberate memory
	try {
	    bo.close();
	    input.close();
	}
	catch (IOException e) {
	    e.printStackTrace();
	}

	return bytes;
    }

    public boolean overwriteWith(String fileData) {

	try {
	    // Borro el archivo actual.
	    _fileConnection.delete();
	}
	catch (IOException e) {
	    Logger.logError(Logger.getLocationMessageFor(this, "overwriteWith()")
		    + " intentando borrar el archivo con el cual tenemos una conexion abierta.", e);
	}

	try {
	    // Creo el nuevo archivo.
	    _fileConnection.create();
	}
	catch (IOException e) {
	    Logger.logError(Logger.getLocationMessageFor(this, "overwriteWith()")
		    + " intentando crear el nuevo archivo.", e);
	}

	return this.writeFile(fileData);
    }

}
